<template>
	<div class="s-canvas">
		<canvas id="s-canvas" :width="contentWidth" :height="contentHeight"></canvas>
	</div>
</template>

<script lang="ts">
import md5 from "js-md5";
import { toRefs, onMounted, watch, defineComponent } from "vue";

export default defineComponent({
	name: "imageCode",
	props: {
		change: {
			// 刷新验证码使用
			type: Boolean,
			default: false
		},
		contentWidth: {
			// 验证码图片宽
			type: Number,
			default: 112
		},
		contentHeight: {
			// 验证码图片高
			type: Number,
			default: 38
		}
	},
	emits: ["getCode"], // 返回验证码加密正确值的函数
	setup(props, context) {
		// 默认值
		const defaultData = {
			identifyCode: "", // 验证码值，未加密的
			identifyCodes: "1234567890", // 生成验证码的元素，可以加入字母
			fontSizeMin: 20, // 图片上验证文字的最小值
			fontSizeMax: 40, // 图片上验证文字的最小值
			backgroundColorMin: 180, // 图片背景色值最小
			backgroundColorMax: 240, // 图片背景色值最大
			colorMin: 50, // 文字色值最小
			colorMax: 160, // 文字色值最大
			lineColorMin: 40, // 干扰线色值最小
			lineColorMax: 120, // 干扰线色值最大
			dotColorMin: 0, // 干扰点色值最小
			dotColorMax: 255, // 干扰点色值最大
			lineSum: 4, // 干扰线数量
			dotSum: 40 // 干扰点数量
		};
		// 父级传递
		const { contentWidth, contentHeight, change } = toRefs(props);

		// 生成一个随机数
		const randomNum = (min: number, max: number) => {
			return Math.floor(Math.random() * (max - min) + min);
		};

		// 生成一个随机的颜色
		const randomColor = (min: number, max: number) => {
			let r = randomNum(min, max);
			let g = randomNum(min, max);
			let b = randomNum(min, max);
			return "rgb(" + r + "," + g + "," + b + ")";
		};

		// 创建图形
		const drawPic = () => {
			let canvas = document.getElementById("s-canvas") as HTMLCanvasElement;
			let ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
			ctx.textBaseline = "bottom";
			// 绘制背景
			ctx.fillStyle = randomColor(defaultData.backgroundColorMin, defaultData.backgroundColorMax);
			ctx.fillRect(0, 0, contentWidth.value, contentHeight.value);
			// 绘制文字
			for (let i = 0; i < defaultData.identifyCode.length; i++) {
				drawText(ctx, defaultData.identifyCode[i], i);
			}
			drawLine(ctx);
			drawDot(ctx);
		};

		// 绘制文字
		const drawText = (ctx: any, txt: any, i: any) => {
			ctx.fillStyle = randomColor(defaultData.colorMin, defaultData.colorMax);
			ctx.font = randomNum(defaultData.fontSizeMin, defaultData.fontSizeMax) + "px SimHei";
			let x = (i + 1) * (contentWidth.value / (defaultData.identifyCode.length + 1));
			let y = randomNum(defaultData.fontSizeMax, contentHeight.value - 5);
			let deg = randomNum(-45, 45);
			// 修改坐标原点和旋转角度
			ctx.translate(x, y);
			ctx.rotate((deg * Math.PI) / 180);
			ctx.fillText(txt, 0, 0);
			// 恢复坐标原点和旋转角度
			ctx.rotate((-deg * Math.PI) / 180);
			ctx.translate(-x, -y);
		};

		// 绘制干扰线
		const drawLine = (ctx: any) => {
			for (let i = 0; i < 4; i++) {
				ctx.strokeStyle = randomColor(defaultData.lineColorMin, defaultData.lineColorMax);
				ctx.beginPath();
				ctx.moveTo(randomNum(0, contentWidth.value), randomNum(0, contentHeight.value));
				ctx.lineTo(randomNum(0, contentWidth.value), randomNum(0, contentHeight.value));
				ctx.stroke();
			}
		};
		// 绘制干扰点
		const drawDot = (ctx: any) => {
			for (let i = 0; i < 60; i++) {
				ctx.fillStyle = randomColor(0, 255);
				ctx.beginPath();
				ctx.arc(randomNum(0, contentWidth.value), randomNum(0, contentHeight.value), 1, 0, 2 * Math.PI);
				ctx.fill();
			}
		};

		// 生成图片
		const makeCode = () => {
			defaultData.identifyCode = "";
			for (let i = 0; i < 4; i++) {
				defaultData.identifyCode += defaultData.identifyCodes[randomNum(0, defaultData.identifyCodes.length)];
			}

			// 绘制图片
			drawPic();
			// 返回加密后的图片验证码值
			context.emit("getCode", md5(defaultData.identifyCode));
		};

		// 初识函数，生成图片
		onMounted(() => {
			makeCode();
		});

		// 监听change变化，重新生成图片
		watch(change, () => {
			makeCode();
		});
	}
});
</script>
